package org.yuyao.gateway.filter;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cloud.gateway.filter.GatewayFilter;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.time.Instant;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicInteger;

/**
 *
 * 限流方案实践2
 *  时间窗口法 的纯内存限流实现
 *
 *  spring:
 *   cloud:
 *     gateway:
 *       discovery:
 *         locator:
 *           enabled: true  # 开启通过服务名自动路由
 *       routes:
 *         - id: yuyao-system
 *           uri: lb://yuyao-system  # 负载均衡到user-service服务
 *           predicates:
 *             - Path=/system/**
 *           filters:
 *             - StripPrefix=1  # 去掉前缀/system
 *             - name: LocalRateLimiterFilter
 *               agrs:
 *                 maxRequests: 5 # 每秒最多 5 次请求
 *    需要上述配置
 *
 */
//@Component
public class LocalRateLimiterFilter extends AbstractGatewayFilterFactory<LocalRateLimiterFilter.Config> {
    private  final Logger logger = LoggerFactory.getLogger(this.getClass());
    // 存储限流计数器：Key = 时间窗口 + 客户端标识, Value = 请求计数
    private final ConcurrentHashMap<String, AtomicInteger> counters = new ConcurrentHashMap<>();

    public LocalRateLimiterFilter() {
        super(Config.class);
    }

    //@Override
   /* public GatewayFilter apply(Config config) {
        return (exchange, chain) -> {
            // 获取客户端标识（例如 IP）
            String clientKey = exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();

            // 计算当前时间窗口（按秒）
            long currentTimeWindow = Instant.now().getEpochSecond();
            String counterKey = currentTimeWindow + ":" + clientKey;

            // 获取或初始化计数器
            AtomicInteger counter = counters.computeIfAbsent(counterKey, k -> new AtomicInteger(0));

            // 判断是否超限
            if (counter.incrementAndGet() > config.getMaxRequests()) {
                // 返回 429 Too Many Requests
                exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
                return exchange.getResponse().setComplete();
            }

            // 清理过期的时间窗口（可选）
            cleanupOldWindows(currentTimeWindow);

            return chain.filter(exchange);
        };
    }
*/


    @Override
    public GatewayFilter apply(Config config) {
        return new GatewayFilter(){
            @Override
            public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {


               //1.获得用户标识
                String clientId=exchange.getRequest().getRemoteAddress().getAddress().getHostAddress();
                logger.info("访问标识:{}",clientId);
                //2.判断用户符合限流标准
                //获取当前的时间秒
                long currentTimeWindow= Instant.now().getEpochSecond();
                String counterKey=currentTimeWindow+":"+clientId;
                //判断是否存在初始化访问值，不存在则写入初始值
                AtomicInteger counter=counters.computeIfAbsent(counterKey,k->new AtomicInteger(0));
                //判断是否超限
                if(counter.incrementAndGet()>config.getMaxRequests()){
                    logger.info("用户->{}->访问{}次啦,不准访问啦",clientId,counter.get());
                    //超限了 返回访问次数过多的限制提醒
                    exchange.getResponse().setStatusCode(HttpStatus.TOO_MANY_REQUESTS);
                    return exchange.getResponse().setComplete();
                }
                //清理过期的时间窗口(可选)
                cleanupOldWindows(currentTimeWindow);
                return chain.filter(exchange);
            }
        };

    }
    // 清理过期的计数器（例如清理 60 秒前的数据）
    private void cleanupOldWindows(long currentTimeWindow) {
        counters.keySet().removeIf(key -> {
            long windowTime = Long.parseLong(key.split(":")[0]);
            return currentTimeWindow - windowTime > 60; // 保留最近 60 秒的窗口
        });
    }

    public static class Config {
        private int maxRequests = 5; // 默认每秒最多 5 次请求

        public int getMaxRequests() {
            return maxRequests;
        }

        public void setMaxRequests(int maxRequests) {
            this.maxRequests = maxRequests;
        }

    }
}
